package org.benetech.util;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

public final class ReflectionUtils {

	/**
	 * Cannot construct.
	 */
	private ReflectionUtils() {
		// cannot construct
	}

	/**
	 * Get the array of classes in a given package. Note that if the same package is in multiple places on the
	 * classpath, only one of the locations will be retrieved.
	 * @param pckgname The name of the package
	 * @return Never null
	 * @throws ClassNotFoundException If the package couldn't be found
	 * @throws IOException If the given resource couldn't be found
	 */
	public static Class[] getClassesInPackage(final String pckgname)
	throws ClassNotFoundException, IOException
	{
		final List<Class> classes = new ArrayList<Class>();
		final List<File> directories = new ArrayList<File>();

		final ClassLoader cld = Thread.currentThread().getContextClassLoader();
		if (cld == null) {
			throw new ClassNotFoundException("Can't get class loader.");
		}
		final String path = pckgname.replace(".", File.separator);
		final Enumeration<URL> resources = cld.getResources(path);
		while (resources.hasMoreElements()) {
			final URL resource = resources.nextElement();
			if (resource == null) {
				throw new ClassNotFoundException("No resource for " + path);
			}
			directories.add(new File(URLDecoder.decode(resource.getPath(), "UTF-8")));
		}

		for (File directory : directories) {
			if (directory.exists()) {
				// Get the list of the files contained in the package
				final String[] files = directory.list();
				for (int i = 0; i < files.length; i++) {
					// we are only interested in .class files
					if (files[i].endsWith(".class")) {
						// removes the .class extension
						final Class clazz = Class.forName(pckgname + '.'
								+ files[i].substring(0, files[i].length() - 6));
						classes.add(clazz);
					}
				}
			} else {
				throw new ClassNotFoundException(pckgname + " does not appear to be a valid package");
			}
		}
		final Class[] classesA = new Class[classes.size()];
		classes.toArray(classesA);
		return classesA;
	}

}
